/***************************************************
> Copyright (C) 2025 ==ASD== All rights reserved.
> File Name: hw.2.c
> Author: asd
> Mail:3319941451@qq.com 
> Created Time: 2025年01月03日 星期五 12时51分29秒
***************************************************/

#include <stdio.h>
#include <mysql/mysql.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <signal.h>
#include <pthread.h>
#include "cJSON.h"

// 定义结构体存储客户端信息
typedef struct ClientInfo {
    int client_socket;
    struct sockaddr_in client_addr;
	char type[20]; 

    char client_id[20];
	char client_phonenumber[20];

} ClientInfo;

// 全局变量，用于存储客户端信息数组  
ClientInfo clients[100];
int client_count = 0;

// MySQL数据库连接相关变量
MYSQL *conn;
struct sockaddr_in client_addr;
// 函数声明
void handle_client(int client_socket);
void register_client(int client_socket,ClientInfo *clients);
void *client_thread(void *arg);
MYSQL *mysql_connection()
{
	MYSQL *conn;

    conn = mysql_init(NULL);
    if (!mysql_real_connect(conn, DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, 0, NULL, 0)) {
        fprintf(stderr, "数据库连接失败: %s\n", mysql_error(conn));
        //close(server_socket);
        exit(EXIT_FAILURE);
    }
	return conn;
}
int create_sock(const char *ip, unsigned short port) 
{
    int server_socket = 0, fd = 0;
    struct sockaddr_in seraddr;
    int ret = 0;
    memset(&seraddr, 0, sizeof(struct sockaddr_in));
    seraddr.sin_family = AF_INET;
    seraddr.sin_addr.s_addr = inet_addr(ip);
    seraddr.sin_port = htons(port);

    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("socket");
        exit(-1);
    }

    ret = bind(server_socket, (struct sockaddr *)&seraddr, sizeof(struct sockaddr));
    if (ret == -1) {
        perror("bind");
        close(server_socket);
        exit(-1);
    }

    ret = listen(server_socket, 5);
    if (ret == -1) {
        perror("listen");
        close(server_socket);
        exit(-1);
    }
	return server_socket;
}

int main() 
{
    // 创建TCP套接字
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("socket");
        exit(-1);
    }

    // 设置服务器地址结构体
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6868);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    // 绑定套接字到地址和端口
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) 
	{
        perror("bind");
        exit(-1);
    }

    // 监听套接字
    if (listen(server_socket, 5) == -1) 
	{
        perror("listen");
        exit(-1);
    }

    // 初始化MySQL连接
    conn = mysql_init(NULL);
    if (conn == NULL) 
	{
        fprintf(stderr, "mysql_init() failed\n");
        exit(-1);
    }

    // 连接到MySQL数据库
    if (mysql_real_connect(conn, "localhost", "root", "password", "client_db", 0, NULL, 0) == NULL) {
        fprintf(stderr, "mysql_real_connect() failed: %s\n", mysql_error(conn));
        exit(-1);
    }

    // 创建epoll实例
    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) 
	{
        perror("epoll_create1");
        exit(-1);
    }

    // 将服务器套接字添加到epoll监听事件中
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = server_socket;
	int ret = 0;
	ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &event);
    if (ret == -1) 
	{
        perror("epoll_ctl");
        exit(-1);
    }

    // 主循环，等待事件发生
    struct epoll_event events[10];
    while (1) {
        int num_events = epoll_wait(epoll_fd, events, 10, -1);
        if (num_events == -1) {
            perror("epoll_wait");
            break;
        }
        for (int i = 0; i < num_events; i++) 
		{
            if (events[i].data.fd == server_socket) 
			{
                // 接受新的客户端连接
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);
                if (client_socket == -1) 
				{
                    perror("Accept failed");
                }
				setnonblocking(client_socket);
				event.events = EPOLLIN;
				event.data.fd = client_socket;
				ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, client_socket, &event);
				/*else 
				{
                    // 为新连接的客户端创建一个线程来处理
                    pthread_t thread_id;
                    pthread_create(&thread_id, NULL, client_thread, (void *)&client_socket);
                }*/
            } else 
			{
                // 处理客户端数据
                handle_client(events[i].data.fd);
            }
        }
    }

    // 关闭MySQL连接
    mysql_close(conn);

    // 关闭服务器套接字
    close(server_socket);

    return 0;
}

void handle_client(int client_socket) {
    // 这里可以根据具体的通信协议解析客户端发送的数据
    char buf[100] = {0};
	
	int ret = 0;
	ret = recv(client_socket,buf,sizeof(buf),0);
	if(ret == -1)
	{
		perror("recv");
		exit(-1);
	}		
	/*if(ret == 0)
	{
		ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
		if (ret == -1)
		{
            perror("epoll_ctl: fd");
            exit(-1);
		}
		close(fd);
	}*/
	
	char type[20] = {0};
	cJSON *json = NULL;
	cJSON *node = NULL;
		
	json = cJSON_Parse(buf);

	node = cJSON_GetObjectItem(json,"type");
	if(node == NULL)
	{
		printf("can't find\n");
		exit(-1);
	}

	if(node->type == cJSON_String)
	{
		strcpy(clients[client_count].type,node->valuestring);
	}
	//如果客户端注册
	if(!strcmp(clients[client_count].type,"registered"))
	{
		node = cJSON_GetObjectItem(json,"phonenumber");
		if(node == NULL)
		{
			printf("can't find\n");
			exit(-1);
		}
		
		if(node->type == cJSON_String)
		{
			strcpy(clients[client_count].client_phonenumber,node->valuestring);
		}
		
		register_client(client_socket, clients);
		pthread_t thread_id;
		pthread_create(&thread_id, NULL, client_thread, (void *)&client_socket);
	}else if(!strcmp(clients[client_count].type,"send"))
	{
		handle_signal_and_send_id(client_socket);
	}else if(!strcmp(clients[client_count].type,"all_data"))
	{
		receive_data_and_authorize();
		pack_data_send_client();
	}
}

void register_client(int client_socket, ClientInfo *clients) {
    // 将客户端信息存储到数组中
    clients[client_count].client_socket = client_socket;
    clients[client_count].client_addr = client_addr;

	
    // 生成客户端ID
    sprintf(clients[client_count].client_id, "%d", client_count+10000);

    // 将客户端信息插入到MySQL数据库中
    char query[200];
    sprintf(query, "INSERT INTO clients (client_id, ip_address, port) VALUES ('%s', '%s', '%d')",
            clients[client_count].client_id, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    if (mysql_query(conn, query)!= 0) {
        fprintf(stderr, "MySQL query failed: %s\n", mysql_error(conn));
    } else {
        printf("Client registered successfully. Client ID: %s\n", clients[client_count].client_id);
    }
    client_count++;
}

void *client_thread(void *arg) {
    int client_socket = *(int *)arg;

    // 获取当前客户端的ID
    char client_id[20];
    strcpy(client_id, clients[client_count - 1].client_id);

    // 发送客户端ID给客户端
    int send_bytes = send(client_socket, client_id, strlen(client_id), 0);
    if (send_bytes == -1) {
        perror("Send failed");
    } else {
        printf("Sent client ID: %s to client\n", client_id);
    }

    // 将线程设置为分离状态
    pthread_detach(pthread_self());
    return NULL;
}

void handle_signal_and_send_id(int client_socket) 
{
    // 创建UDP套接字
   
	/*MYSQL *conn = mysql_connection();
	int ret;
	mysql_query(conn, "SET NAMES utf8"); // 设置中文字符集

	char sql_buf[128] = "select * from client";
	ret = mysql_query(conn, sql_buf); // 执行sql语句
	if (ret != 0) {
		printf("mysql query failed\n");
	}
	MYSQL_RES *res;
	MYSQL_ROW row;
	
	res = mysql_store_result(conn); // 存储结果
	char client_id[50];
	memset(&client_id,0,sizeof(client_id));
	for (int i = 0;i < mysql_num_rows(res); i++) 
	{ // 行
		row = mysql_fetch_row(res);
		for (int j = 0;j < mysql_num_fields(res); j++) 
		{
			strcpy(client_id,row[j]);
		}
	}*/
    // 获取客户端ID并发送给客户端转化成cJSON发给客户端
	char type[20] = {"can_send_ID"};
	cJSON *json = NULL;
	json = cJSON_CreateObject();
		
	cJSON_AddItemToObject(json,"type",cJSON_CreateString(type));
	cJSON_AddItemToObject(json,"client_id",cJSON_CreateString(client_id));
	char *buf = NULL;

	buf = cJSON_Print(json);

	puts(buf);
	ret = send(client_socket, buf, strlen(buf), 0);
    if (ret == -1) 
	{
        perror("发送客户端ID失败");
        close(client_socket);
        exit(EXIT_FAILURE);
    }
	cJSON_Delete(json);
}
void receive_data_and_authorize() {
   
		printf_data(json);
		node = cJSON_GetObjectItem(json, "authorization");
        if (node == NULL) 
		{
            printf("can't find\n");
            exit(-1);
		}
        if (node->type == cJSON_String) 
		{
            strcpy(authorization, node->valuestring);
        }
	}


    // 将接收到的数据存入文件
    char file_name[50];
    sprintf(file_name, "received_data_%d.txt",sequence_number);
    FILE *fp = fopen(file_name, "wb");
    if (fp == NULL) {
        perror("打开文件失败");
        close(server_socket);
        exit(EXIT_FAILURE);
    }
    fwrite(data, 1, strlen(data), fp);
    fclose(fp);

    // 将授权信息和文件名存入数据库
    MYSQL *conn = mysql_connection();
   

    char query[200];
    sprintf(query, "INSERT INTO authorization (sequence_number,file_name,authorization) VALUES ('%d','%s','%s','%s')", sequence_number,file_type, file_name, authorization);
    if (mysql_query(conn, query)) {
        fprintf(stderr, "数据库插入失败: %s\n", mysql_error(conn));
    }
	
	sequence_number++;
	
    mysql_close(conn);
    close(server_socket);
}
char *printf_data(cJSON *json)
{
    cJSON *node = NULL;
    node = cJSON_GetObjectItem(json, "data");
    if (node == NULL)
    {
        printf("can't find data\n");
        return;
    }
    else if (node->type == cJSON_String)
    {
        // 将data字段对应的字符串解析为JSON对象，因为其内部还有结构
        cJSON *data_json = cJSON_Parse(node->valuestring);
        if (data_json == NULL)
        {
            printf("Failed to parse data JSON string.\n");
            return;
        }

        cJSON *file_type_node = cJSON_GetObjectItem(data_json, "file_type");
        cJSON *content_node = cJSON_GetObjectItem(data_json, "content");

        if (file_type_node == NULL || content_node == NULL)
        {
            printf("Incomplete data JSON structure.\n");
            cJSON_Delete(data_json);
            return;
        }

        if (file_type_node->type == cJSON_String && content_node->type == cJSON_String)
        {
            printf("文件类型: %s\n", file_type_node->valuestring);
            printf("内容（示例展示，可能是Base64编码等形式的数据）: %s\n", content_node->valuestring);

            // 这里可以根据文件类型做进一步的处理，比如如果是音频，可以调用音频处理相关函数
            // 如果是视频，可以调用视频处理相关函数等，以下是简单示例伪代码
            if (strcmp(file_type_node->valuestring, "text") == 0)
            {
               
            }
            else if (strcmp(file_type_node->valuestring, "video") == 0)
            {
                // 调用视频处理函数，比如解码Base64数据、播放视频等，此处仅为示意
                // video_process(content_node->valuestring);
            }
        }
        else
        {
            printf("Invalid data types in data JSON structure.\n");
        }

        cJSON_Delete(data_json);
    }
}